<?php

namespace tmcore\traits;

trait ModelTrait
{
    public static function get($where)
    {
        if (!is_array($where)) {
            return self::find($where);
        } else {
            return self::where($where)->find();
        }
    }

    /**
     * 添加多条数据
     * @param $group
     * @param integer $limit
     * @return mixed
     */
    public static function addAll($group, $limit = 0)
    {
        return (new self())->insertAll($group, $limit);
    }

    /**
     * 增加一条数据
     * @param array $data 数据
     * @param bool $is_return_pk 返回自增主键
     * @return int|boolean
     */
    public static function add($data, $is_return_pk = false)
    {
        $result = self::create($data);
        if(empty($result->id)) {
            return false;
        } else {
            return $is_return_pk?$result->id:true;
        }
    }

    /**
     * 修改一条数据
     * @param array $data
     * @param int $id
     * @param string $field
     * @return bool
     */
    public static function edit($data, $id, $field = null)
    {
        $model = new self;
        if (!$field) $field = $model->getPk();
        $res = $model->update($data, [$field => $id]);
        return false !== $res;
    }


    /**
     * 查询一条数据是否存在
     * @param $map
     * @param string $field
     * @return bool 是否存在
     */
    public static function be($map, $field = '')
    {
        $model = (new self);
        if (!is_array($map) && empty($field)) $field = $model->getPk();
        $map = !is_array($map) ? [$field => $map] : $map;
        return 0 < $model->where($map)->count();
    }

    /**
     * 删除数据
     * @param int|array $data
     * @param bool $force 是否真实删除
     * @return bool 返回成功失败
     */
    public static function del($data, $force = false)
    {
        if(is_array($data)) {
            $resultSet = (new self)->select($data);
            foreach ($resultSet as $result) {
                $result->force($force)->delete();
            }
            return true;
        } else {
            $model = self::get($data);
            if(!$model)return false;
            return false !== $model->force($force)->delete();
        }
    }

    /**
     * 分页函数
     * @param array $where 查询条件
     * @param array $page limit-分页条数 page-分页页数
     * @param string|array $field 返回字段
     * @param array $order 排序
     * @param array|string $append 关联属性
     * @param array $with 关联查询
     * @param array $extend 扩展参数
     * @return array
     */
    public static function page($where, $page = ['limit' => '20'], $field = '*', $order = ['id'=>'desc'], $append = [], $with = [], $extend = [])
    {
        // 重新写分页功能
        $page['page'] = $page['page'] ?? 1;
        $page['limit'] = $page['limit'] ?? 20;

        $count = self::where($where)->count();
        $list = self::where($where)
            ->field($field)
            ->append($append)
            ->with($with)
            ->page($page['page'], $page['limit'])
            ->order($order)->select()->toArray();

        $page_data = [
            'page_total' => $count,
            'page_num' => $page['page'],
            'page_limit' => $page['limit'],
            'list' => $list
        ];
        if($extend) $page_data['extend'] = $extend;
        return $page_data;
    }

    /**
     * 导出分页函数（支持导出预览）
     * @param array $export_params 导出参数
     * @param array $where 查询条件
     * @param array $page limit-分页条数 page-分页页数
     * @param string $field 返回字段
     * @param array $order 排序
     * @param array $append 关联属性
     * @param array $with 关联查询
     * @return array
     */
    public static function exportPage($export_params, $where, $page = ['limit' => '1000'], $field = '*', $order = ['id'=>'desc'], $append = [], $with = [])
    {
        if($export_params['export_type'] == 1) { //导出数据预览
            $page['page'] = $page['page'] ?? 1;
            $page['limit'] = $page['limit'] ?? 1000;
            $count = self::where($where)->count();
            $page_data = [
                'page_total' => $count,
                'page_num' => $page['page'],
                'page_limit' => $page['limit'],
                'list' => []
            ];
            if($export_params) $page_data['extend'] = $export_params;
            return $page_data;
        } else {
            if(!$export_params['is_async']) { //是否异步
                $count = self::where($where)->count();
                if($count) {
                    $export_params['page_end'] = intval(min([ceil($count/$export_params['page_limit']), $export_params['page_end']]));
                    $export_params['page_start'] = $export_params['page_start']?:1;
                    if($export_params['is_page']) {
                        $limit_start = ($export_params['page_start'] - 1) * $export_params['page_limit'];
                        $limit_num = $export_params['page_limit'] * ($export_params['page_end'] - $export_params['page_start'] + 1);
                    } else {
                        $limit_start = 0;
                        $limit_num = $count;
                    }

                    // 执行耗时操作，包含很多循环处理 append循环 + foreach循环 + 全字段查询 + sql耗时
                    // 注意：append属性中的数据库操作，统一放在foreach循环中处理，避免重复执行sql
                    // 去除each闭包函数，有性能问题，返回后自行处理
                    $list = self::where($where)
                        ->field($field)
                        ->append($append)
                        ->with($with)
                        ->order($order)
                        ->limit($limit_start,$limit_num)
                        ->select()->toArray();
                } else {
                    $list = [];
                }
                return ['list' => $list, 'extend' => $export_params];
            } else {
                return ['list' => [], 'extend' => $export_params];
            }
        }
    }

    /**
     * 获取时间段之间的model
     * @param array $where 参数 ['data' => 'year']
     * @param string $prefix 查询字段名
     * @param string $data 时间类型 today-今天 week-一周 last week-上周 month-一个月 last month-上一个月 year-一年 last year-上一年 yesterday-昨天 quarter-一个季度 lately7-过去7天 lately30-过去30天
     * @param string $field 时间段分割字符
     * @return ModelTrait
     */
    public static function getModelTime($where, $prefix = 'create_time', $data = 'data', $field = ' - ')
    {
        $model = new self;
        if (!isset($where[$data])) return $model;
        switch ($where[$data]) {
            case 'today':
            case 'week':
            case 'last week':
            case 'month':
            case 'last month':
            case 'year':
            case 'last year':
            case 'yesterday':
                $model = $model->whereTime($prefix, $where[$data]);
                break;
            case 'quarter':
                list($startTime, $endTime) = self::getMonth();
                $model = $model->where($prefix, '>', strtotime($startTime));
                $model = $model->where($prefix, '<', strtotime($endTime));
                break;
            case 'lately7':
                $model = $model->where($prefix, 'between', [strtotime("-7 day"), time()]);
                break;
            case 'lately30':
                $model = $model->where($prefix, 'between', [strtotime("-30 day"), time()]);
                break;
            default:
                if (strstr($where[$data], $field) !== false) {
                    list($startTime, $endTime) = explode($field, $where[$data]);
                    $model = $model->where($prefix, '>', strtotime($startTime));
                    $model = $model->where($prefix, '<', strtotime($endTime));
                }
                break;
        }
        return $model;
    }

    /**
     * 获取本季度 time
     * @param string $time
     * @param int $ceil
     * @return array
     */
    public static function getMonth($time = '', $ceil = 0)
    {
        if ($ceil != 0)
            $season = ceil(date('n') / 3) - $ceil;
        else
            $season = ceil(date('n') / 3);
        $firstDay = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
        $lastDay = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
        return array($firstDay, $lastDay);
    }

    /**
     * 自动添加时间戳
     * @param array $data
     * @param array $fields
     * @param null $time
     * @return array
     */
    public static function autoAddTimestamp($data = [], $fields = ['create_time','update_time'], $time = null)
    {
        if($fields) {
            $cur_time = $time?$time:time();
            foreach ($fields as $key => $value) {
                if(empty($data[$value])) $data[$value] = $cur_time;
            }
        }
        return $data;
    }

    /**
     * 高精度 加法
     * @param array $where 查询条件
     * @param string $incField 相加的字段
     * @param float|int $inc 加的值
     * @param int $acc 精度
     * @return bool
     */
    public static function bcInc($where, $incField, $inc, $acc = 2)
    {
        if (!is_numeric($inc)) return false;
        $result = self::where($where)->find();
        if (!$result) return false;
        $new = bcadd($result[$incField], $inc, $acc);
        $result->$incField = $new;
        return false !== $result->save();
    }

    /**
     * 高精度 减法
     * @param array $where 查询条件
     * @param string $decField 相减的字段
     * @param float|int $dec 减的值
     * @param bool $minus 是否可以为负数
     * @param int $acc 精度
     * @return bool
     */
    public static function bcDec($where, $decField, $dec, $minus = false, $acc = 2)
    {
        if (!is_numeric($dec)) return false;
        $result = self::where($where)->find();
        if (!$result) return false;
        if (!$minus && $result[$decField] < $dec) return false;
        $new = bcsub($result[$decField], $dec, $acc);
        $result->$decField = $new;
        return false !== $result->save();
    }

    /**
     * @param null $model
     * @return ModelTrait
     */
    protected static function getSelfModel($model = null)
    {
        return $model == null ? (new self()) : $model;
    }

}